<template>
  <codemirror ref="codemirror" v-model="code" :options="cmOptions" @ready="onReady"></codemirror>
</template>
<script>
import { codemirror } from "vue-codemirror";
import { operatorArr, FUNC } from "./config";
import * as calculate from "@/util/xc/calculate";

import "codemirror/lib/codemirror.css";
import "codemirror/theme/material.css";
import "codemirror/mode/javascript/javascript.js";
// lint
// import "codemirror/addon/lint/lint";
// import "codemirror/addon/lint/javascript-lint";
// import "codemirror/addon/lint/lint.css";
// hint
// import "codemirror/addon/hint/show-hint";
// import "codemirror/addon/hint/javascript-hint";
// import "codemirror/addon/hint/show-hint.css";

import { getFormula } from "./handleFormula";
export default {
  name: "CustomFormula",
  components: { codemirror },
  props: {
    checkingIn: {
      type: Array,
      default: () => []
    },
    payment: {
      type: Array,
      default: () => []
    }
  },
  data() {
    this.classNameArr = ["checking", "reward", "func"];
    return {
      ...calculate,
      code: ``,
      cmOptions: {
        tabSize: 2,
        indentUnit: 2,
        mode: "text/javascript",
        // theme: "base16-dark",
        // lineNumbers: true, // 左侧行号
        matchBrackets: true // 括号匹配
        // showHint: {
        // completeSingle: false
        // }
        // lint: true,
        // lineWrapping: true, // 自动换行
      },
      operatorArr,
      FUNC
    };
  },
  methods: {
    // 事件
    ...{
      onReady(e) {
        // 粘贴
        e.on("inputRead", () => {
          this.executeRender();
        });
        e.on("cursorActivity", () => {
          // 显示提示
          // this.$refs.codemirror.codemirror.showHint();
        });
      }
    },
    // 返填
    ...{
      callback(str = "") {
        this.code = str;
        this.executeRender();
      },
      executeRender() {
        const arr = this.code.split("\n");
        this.$nextTick(() => {
          arr.forEach(this.disposeRow);
        });
        this.$refs.codemirror.codemirror.focus();
      },

      /**
       * 替换数据
       * @param {String} 行数据
       * @param {String} 主要值
       * @param {String} 辅助值
       * @param {Number} 行号
       */
      replaceText(str, name, line, type, assist = "") {
        const regExp = new RegExp(name + assist, "g");
        const arr = str.matchAll(regExp);
        let o = arr.next();
        while (!o.done) {
          const anchor = { ch: o.value.index, line };
          const head = { ch: anchor.ch + name.length, line };
          this.addMarkTextDom(name, type, anchor, head);
          o = arr.next();
        }
      },

      /** 处理行数据 */
      disposeRow(str, line) {
        // console.log(this.checkingIn, this.payment, this.FUNC, line);
        this.FUNC.forEach(item => {
          this.replaceText(str, item.type, line, 3, "\\(");
        });
        this.checkingIn.forEach(item => {
          this.replaceText(str, "#" + item.name + "#", line, 1);
        });
        this.payment.forEach(item => {
          this.replaceText(str, "#" + item.name + "#", line, 2);
        });
      }
    },
    // 插入
    ...{
      addField(e, type) {
        let name = type == 3 ? e.type : "#" + e.name + "#";

        //获取codemirror光标位置
        const pos1 = this.$refs.codemirror.codemirror.getCursor();
        const pos2 = {};
        pos2.line = pos1.line;
        pos2.ch = pos1.ch;
        console.log(pos1);

        if (type == 4) {
          const n = e.insert || e.label;
          // const endPos = { line: pos2.line, ch: pos2.ch + n.length };
          this.$refs.codemirror.codemirror.replaceRange(n, pos2); //先插入字符串
          // this.addMarkTextDom(n, type, pos2, endPos);
        } else {
          const endPos = { line: pos2.line, ch: pos2.ch + name.length };

          this.$refs.codemirror.codemirror.replaceRange(name + (e.formula || ""), pos2); //先插入字符串

          this.addMarkTextDom(name, type, pos2, endPos);
        }
        // this.content = this.$refs.codemirror.codemirror.getValue(); //获取codemirror内容
        this.$refs.codemirror.codemirror.focus();
      },

      /** 添加指定元素,改变颜色 */
      addMarkTextDom(name, type, posStart, posEnd) {
        let className = this.classNameArr[Number(type) - 1];
        //制作标签dom(颜色样式自行设置)
        var dom = document.createElement("span");
        dom.className = "cm-" + className;
        dom.style = "margin:0 3px;";
        dom.innerHTML = name;
        //再对插入字符串进行标签制定（其实就是在codemirror中动态添加标签）
        this.$refs.codemirror.codemirror.markText(posStart, posEnd, {
          replacedWith: dom
        });
      }
    },
    checkFormula(bol) {
      return new Promise(async (resolve, reject) => {
        // 校验公式
        try {
          if (!this.code) {
            this.$message({ message: "请输入公式", type: "warning" });
            reject(false);
            return;
          }
          const obj = { str: this.code, checkingIn: this.checkingIn, payment: this.payment };

          const { str: formula, salaryRule } = getFormula(obj);
          const fn = new Function(formula).bind(this);
          const result = fn();
          console.log(result, salaryRule);
          if (salaryRule == 10) {
            // 逻辑公式才需要后台验证
            const formData = new FormData();
            formData.append("formula", formula.replace(/this./g, ""));
            await this.$api.CustomFormula.valid(formData)
              .then(res => res.data)
              .catch(() => {
                reject(false);
                return false;
              });
          }
          if (bol) resolve(getFormula(obj, true));
          else resolve(true);
        } catch (err) {
          this.$message({ message: "公式语法错误", type: "warning" });
          reject(false);
        }
      });
    }
  }
};
</script>
<style lang="less">
.CodeMirror-hints {
  z-index: 500000;
}
</style>
<style lang="less" scoped>
.vue-codemirror,
:deep( .CodeMirror ){
  height: 100%;
  .cm- {
    &checking {
      color: #9278f4;
    }
    &reward {
      color: #9278f4;
    }
    &func {
      color: #22bcff;
    }
  }
}
</style>
